<?php
declare (strict_types = 1);

namespace app\service\basic\auth;

use think\Model;
use think\helper\Str;
use app\tools\HasherTool;
use app\facade\HasherFacade;
use think\contract\Arrayable;

class ModelUserProvider implements UserProvider
{
    /**
     * The user model.
     *
     * @var string
     */
    protected $model;

    /**
     * The hasher implementation.
     *
     * @var HasherTool
     */
    protected $hasher;

    /**
     * Create a new database user provider.
     *
     * @param  string  $model
     * @return void
     */
    public function __construct($model)
    {
        $this->model = $model;
        $this->hasher = HasherFacade::instance();
    }

    /**
     * Retrieve a user by the given credentials.
     *
     * @param mixed $identifier
     * @return array|Model
     */
    public function retrieveById($identifier)
    {
        $model = $this->createModel();

        return $model
            ->field($model->getAuthVisibleFields())
            ->where($model->getAuthIdentifierName(), $identifier)
            ->findOrEmpty();
    }

    /**
     * Retrieve a user by the given credentials.
     *
     * @param array $credentials
     * @return Model|void
     */
    public function retrieveByCredentials(array $credentials)
    {
        if (empty($credentials) ||
           (count($credentials) === 1 &&
            array_key_exists('password', $credentials))) {
            return ;
        }

        // First we will add each credential element to the query as a where clause.
        // Then we can execute the query and, if we found a user, return it in a
        // Eloquent User "model" that will be utilized by the Guard instances.
        $model = $this->createModel();

        foreach ($credentials as $key => $value) {
            if (Str::contains($key, 'password')) {
                continue;
            }

            if (is_array($value) || $value instanceof Arrayable) {
                $model = $model->whereIn($key, $value)->field($model->getAuthVisibleFields());
            } else {
                $model = $model->where($key, $value)->field($model->getAuthVisibleFields());
            }
        }
        return $model->findOrEmpty();
    }

    /**
     * Validate a user against the given credentials.
     *
     * @param Model $user
     * @param array $credentials
     * @return bool
     */
    public function validateCredentials($user, array $credentials)
    {
        $plain = $credentials['password'];

        return $this->hasher->check($plain, $user->getAuthPassword());
    }

    /**
     * Validate a user state.
     *
     * @param Model $user
     * @return bool
     */
    public function validateState($user)
    {
        return $user->validateState();
    }

    /**
     * Create a new instance of the model.
     *
     * @return Model
     */
    public function createModel()
    {
        $class = '\\'.ltrim($this->model, '\\');

        return new $class;
    }

    /**
     * Gets the name of the Eloquent user model.
     *
     * @return string
     */
    public function getModel()
    {
        return $this->model;
    }

    /**
     * Sets the name of the Eloquent user model.
     *
     * @param  string  $model
     * @return $this
     */
    public function setModel($model)
    {
        $this->model = $model;

        return $this;
    }
}
